package com.xbongbong.parent.es;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.SizeConstant;
import com.xbongbong.paas.domain.entity.PaasFormSubDataEntity;
import com.xbongbong.paas.elasticsearch.model.PaasFormSubDataEsModel;
import com.xbongbong.paas.elasticsearch.pojo.dto.InsertDTO;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.pojo.dto.PaasFormDataEsInitDTO;
import com.xbongbong.paas.pojo.dto.PaasFormDataEsMappingDTO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsInitVO;
import com.xbongbong.paas.redis.RedisTimeConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.model.PaasFormSubDataModel;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.CompanyModel;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.indices.GetMappingsRequest;
import org.elasticsearch.client.indices.GetMappingsResponse;
import org.elasticsearch.cluster.metadata.MappingMetaData;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * ElasticSearch 初始化相关抽象类接口
 * @author zheng.li
 **/
@Slf4j
public abstract class AbstractPaasElasticSearchInit implements PaasElasticSearchInitInterface {

    @Resource
    private CompanyModel companyModel;

    @Resource
    private CompanyConfigModel companyConfigModel;

    @Resource
    private PaasFormSubDataModel paasFormSubDataModel;

    @Resource
    private PaasFormSubDataEsModel paasFormSubDataEsModel;

    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;

    @Override
    public PaasFormDataEsInitVO initAllByBuss(PaasFormDataEsInitDTO paasFormDataEsInitDTO) throws XbbException {
        PaasFormDataEsInitVO paasFormDataEsInitVO = new PaasFormDataEsInitVO();
        Integer byCorpid = paasFormDataEsInitDTO.getByCorpid();
        if(byCorpid != null && Objects.equals(0,byCorpid)){
            paasFormDataEsInitDTO.setCorpid(null);
        }
        log.info("开始处理=====");
        List<Integer> businessTypeList = paasFormDataEsInitDTO.getBusinessTypeList();
        Long updateTimeStart = paasFormDataEsInitDTO.getUpdateTimeStart();
        if(updateTimeStart != null && updateTimeStart > 0 ){
            Map<String, Object> param = new HashMap<>();
            param.put("del", 0);
            param.put("status", 1);
            param.put("columns", "corpid");
            param.put("feeEndTimeStart", updateTimeStart);
            List<CompanyEntity> companyEntities = companyModel.findEntitys(param);
            int count = 0;
            for (CompanyEntity companyEntity : companyEntities) {
                paasFormDataEsInitDTO.setCorpid(companyEntity.getCorpid());
                for (Integer integer : businessTypeList) {
                    IndexTypeEnum indexTypeEnum;
                    if(Objects.equals(IndexTypeEnum.IDX_FORM_DATA.getCode(),integer)){
                        indexTypeEnum = IndexTypeEnum.IDX_FORM_DATA;
                    }else{
                        indexTypeEnum =  EsUtil.getIndexTypeEnum(paasFormDataEsInitDTO.getSaasMark(),integer);
                    }

                    doInit(paasFormDataEsInitDTO, indexTypeEnum);
                }
                count++;
                log.info(companyEntity.getCorpid() + "=====count====="+ count + "====size==="+companyEntities.size());
            }
        }else {
            for (Integer integer : businessTypeList) {
                IndexTypeEnum indexTypeEnum;
                if(Objects.equals(IndexTypeEnum.IDX_FORM_DATA.getCode(),integer)){
                    indexTypeEnum = IndexTypeEnum.IDX_FORM_DATA;
                }else{
                    indexTypeEnum =  EsUtil.getIndexTypeEnum(paasFormDataEsInitDTO.getSaasMark(),integer);
                }
                doInit(paasFormDataEsInitDTO, indexTypeEnum);

                log.info(integer + "===== success =====");
            }
        }
        log.info("初始化结束success=====");
        return paasFormDataEsInitVO;
    }

    @Override
    public PaasFormDataEsInitVO initSubData(PaasFormDataEsInitDTO paasFormDataEsInitDTO) throws Exception {
        PaasFormDataEsInitVO paasFormDataEsInitVO = new PaasFormDataEsInitVO();
        PaasFormDataEsMappingDTO paasFormDataEsMappingDTO = new PaasFormDataEsMappingDTO();
        Integer byCorpid = paasFormDataEsInitDTO.getByCorpid();
        if(byCorpid != null && Objects.equals(0,byCorpid)){
            paasFormDataEsInitDTO.setCorpid(null);
        }
        BeanUtil.copyProperties(paasFormDataEsInitDTO, paasFormDataEsMappingDTO);
        if (paasFormDataEsMappingDTO.getSaasMark().equals(SaasMarkEnum.PAAS.getCode())) {
            return paasFormDataEsInitVO;
        }
        Integer pageSize = paasFormDataEsInitDTO.getPageSize();
        if (pageSize == null) {
            paasFormDataEsInitDTO.setPageSize(SizeConstant.PAGE_SIZE);
        }

        IndexTypeEnum indexTypeEnum = EsHelper.getIndexTypeEnum(paasFormDataEsMappingDTO);
        Integer businessType = paasFormDataEsMappingDTO.getBusinessType();
        if (businessType == null || businessType.equals(0)) {
            log.error("businessType为空");
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        String value = companyConfigModel.getByConfigAlias(CompanyConfigEnum.ELASTICSEARCH_INDEX.getAlias(), CompanyConfigEnum.ELASTICSEARCH_INDEX.getAlias(), "0", "0", RedisTimeConstant.TEN_MINUTES);
        Set<String> corpidSet = new HashSet<>();
        if (StringUtil.isNotEmpty(value)) {
            corpidSet = new HashSet<>(JSON.parseArray(value, String.class));
        }
        log.info(" =========subForm data start==========");
        Map<String, Object> params = BeanUtil.convertBean2Map(paasFormDataEsInitDTO, true);
        params.put("orderByStr", "id");
        boolean flag = true;
        while (flag) {
            List<? extends PaasFormSubDataEntity> list = paasFormSubDataModel.getSubDataList(params, indexTypeEnum);
            if (list == null || list.isEmpty()) {
                flag = false;
            } else {
                params.put("idGte", list.get(list.size() - 1).getId());
                if (corpidSet.contains(list.get(0).getCorpid()) && Objects.equals(XbbRefTypeEnum.CUSTOMER_SUBFORM.getCode(), businessType)) {
                    indexTypeEnum = IndexTypeEnum.IDX_SAAS_CUSTOMER_SUB_SPECIAL;
                }
                paasFormSubDataEsModel.insertBatch(list, indexTypeEnum);
                log.info(indexTypeEnum + "=====id====="+ list.get(list.size()-1).getId() + "===size=="+list.size());
            }

        }
        return paasFormDataEsInitVO;
    }

    /**
     * 获取索引的字段mapping映射
     * @param indexTypeEnum 索引类型
     * @return json
     * @throws IOException  IOException
     * @throws XbbException 系统异常
     */
    protected JSONObject getMappingMap(IndexTypeEnum indexTypeEnum) throws IOException, XbbException {
        GetMappingsRequest getMappingsRequest = new GetMappingsRequest();
        getMappingsRequest.indices(indexTypeEnum.getIndex());
        GetMappingsResponse mappingsResponse = xbbElasticsearchRestTemplate.getRestHighLevelClient(indexTypeEnum.getIndex()).indices().getMapping(getMappingsRequest, RequestOptions.DEFAULT);
        Map<String, MappingMetaData> map = mappingsResponse.mappings();
        String key = "";
        for (String s : map.keySet()) {
            key = s;
            //第一层也就一个key,是index的名称   indexTypeEnum.getRealName() 是固定的，可能会用到切索引，所以要动态获取index
            break;
        }
        MappingMetaData mappingMetaData = map.get(key);
        Map<String, Object> sourceAsMap = mappingMetaData.sourceAsMap();
        Map properties = (Map) sourceAsMap.get("properties");
        return new JSONObject(properties);
    }

    /**
     * 排除不在预期内的值
     * @param outKeySet 排除的key
     * @param dataKeySet
     * @param insertDTO
     */
    protected void excludeKey(Set<String> outKeySet, Set<String> dataKeySet, InsertDTO insertDTO) {
        Map<String, Object> source = insertDTO.getSource();
        JSONObject data = (JSONObject) source.get("data");
        if (CollectionsUtil.isNotEmpty(dataKeySet) && data != null && !data.isEmpty()) {
            data.keySet().retainAll(dataKeySet);
        }
        source.keySet().retainAll(outKeySet);
        insertDTO.setSource(source);
    }

    /**
     * data内子表单处理
     * @param data data数据
     * @param subFormKeySet 子表单1 字段设置
     * @param subFormKeySecSet 子表单2 字段设置
     */
    protected void subFormDataRetain(JSONObject data,Set<String> subFormKeySet,Set<String> subFormKeySecSet) {
        //特殊子表单内数据的清理
        JSONArray subFormDataArray = data.getJSONArray("subForm_1");
        dataSubFormRetain(subFormKeySet, subFormDataArray);
        //工作报告可能有第二个子表单
        JSONArray subFormDataSecArray = data.getJSONArray("subForm_2");
        dataSubFormRetain(subFormKeySecSet, subFormDataSecArray);
    }

    private void dataSubFormRetain(Set<String> subFormKeySet, JSONArray subFormDataArray) {
        if(subFormDataArray != null && !subFormDataArray.isEmpty()){
            if(CollectionsUtil.isNotEmpty(subFormKeySet)){
                for (int i = 0; i < subFormDataArray.size(); i++) {
                    JSONObject subFormData = subFormDataArray.getJSONObject(i);
                    subFormData.keySet().retainAll(subFormKeySet);
                }
            }
        }
    }


}
